package cn.edu.lcu.cs.javaprogramming.thread.ticketoffice.safe;

import java.util.Random;

/**
 * 售票窗口线程
 *
 * @author ling
 * @date 2022/5/30 16:10
 */
public class TicketWindow implements Runnable {
    private Integer remainingTicket;


    public TicketWindow(int remainingTicket) {
        this.remainingTicket = remainingTicket;
    }

    @Override
    public void run() {
        Random random = new Random();
        while (remainingTicket > 0) {
            try {
                Thread.sleep(random.nextInt(2000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // 同步代码块
            // 给下列代码块加一把锁，锁具有排他性。
            // 获取锁的线程才能进入并执行同步代码块
            // 没有获取锁的线程只能等待
            // 代码块结束，锁自动打开，等待队列上的线程被唤醒，竞争加锁。
            // 同步代码块的粒度越小越好
            synchronized (remainingTicket) {
                // 在出票前的最后一刻，再次确认余票数量
                // 如果尚有余票，就发售，即对共享变量进行写操作
                if (remainingTicket > 0) {
                    // 在remainingTicket--之前，极端情况下，别的线程抢先把remainingTicket写为0，再递减，结果又错了。
                    System.out.println(Thread.currentThread().getName() + " 正在发售第 " + remainingTicket-- + " 张票");
                }
            }
        }
        System.err.println(Thread.currentThread().getName() + " 票已售罄！");
    }
}
